package com.lktx.sso.config;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.config.SaOAuth2ServerConfig;
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts;
import cn.dev33.satoken.oauth2.data.generate.SaOAuth2DataGenerate;
import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
import cn.dev33.satoken.oauth2.data.model.CodeModel;
import cn.dev33.satoken.oauth2.data.model.loader.SaClientModel;
import cn.dev33.satoken.oauth2.data.model.request.RequestAuthModel;
import cn.dev33.satoken.oauth2.error.SaOAuth2ErrorCode;
import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception;
import cn.dev33.satoken.oauth2.processor.SaOAuth2ServerProcessor;
import cn.dev33.satoken.oauth2.strategy.SaOAuth2Strategy;
import cn.dev33.satoken.oauth2.template.SaOAuth2Template;
import cn.dev33.satoken.router.SaHttpMethod;
import cn.dev33.satoken.util.SaResult;
import cn.hutool.core.util.StrUtil;

import java.util.List;
import java.util.function.Consumer;

public class SSoSaOAuth2ServerProcessor extends SaOAuth2ServerProcessor {
    public static SSoSaOAuth2ServerProcessor instance = new SSoSaOAuth2ServerProcessor();

    private void cacheNonce(String code) {
        //重写这段代码
        String nonce = SaHolder.getRequest().getParam("nonce");
        if (StrUtil.isNotEmpty(nonce)){
            OAuthConfig.CACHE_CODE_NONCE.put(code, nonce);
        }
    }


    @Override
    public Object authorize() {
        SaRequest req = SaHolder.getRequest();
        SaResponse res = SaHolder.getResponse();
        SaOAuth2ServerConfig cfg = SaOAuth2Manager.getServerConfig();
        SaOAuth2DataGenerate dataGenerate = SaOAuth2Manager.getDataGenerate();
        SaOAuth2Template oauth2Template = SaOAuth2Manager.getTemplate();
        String responseType = req.getParamNotNull(SaOAuth2Consts.Param.response_type);
        this.checkAuthorizeResponseType(responseType, req, cfg);
        Object loginId = SaOAuth2Manager.getStpLogic().getLoginIdDefaultNull();
        if (loginId == null) {
            return SaOAuth2Strategy.instance.notLoginView.get();
        } else {
            RequestAuthModel ra = SaOAuth2Manager.getDataResolver().readRequestAuthModel(req, loginId);
            SaOAuth2Strategy.instance.userAuthorizeClientCheck.run(ra.loginId, ra.clientId);
            oauth2Template.checkRedirectUri(ra.clientId, ra.redirectUri);
            oauth2Template.checkContractScope(ra.clientId, ra.scopes);
            boolean isNeedCarefulConfirm = oauth2Template.isNeedCarefulConfirm(ra.loginId, ra.clientId, ra.scopes);
            if (isNeedCarefulConfirm) {
                SaClientModel cm = oauth2Template.checkClientModel(ra.clientId);
                if (!cm.getIsAutoConfirm()) {
                    return SaOAuth2Strategy.instance.confirmView.apply(ra.clientId, ra.scopes);
                }
            }

            if (SaOAuth2Consts.ResponseType.code.equals(ra.responseType)) {
                CodeModel codeModel = dataGenerate.generateCode(ra);
                String redirectUri = dataGenerate.buildRedirectUri(ra.redirectUri, codeModel.code, ra.state);
                cacheNonce(codeModel.code);
                return res.redirect(redirectUri);
            } else if (SaOAuth2Consts.ResponseType.token.equals(ra.responseType)) {
                AccessTokenModel at = dataGenerate.generateAccessToken(ra, false, null);
                String redirectUri = dataGenerate.buildImplicitRedirectUri(ra.redirectUri, at.accessToken, ra.state);
                return res.redirect(redirectUri);
            } else {
                throw (new SaOAuth2Exception("无效 response_type: " + ra.responseType)).setCode(30125);
            }
        }
    }


    @Override
    public Object doConfirm() {
        SaRequest req = SaHolder.getRequest();
        String clientId = req.getParamNotNull(SaOAuth2Consts.Param.client_id);
        Object loginId = SaOAuth2Manager.getStpLogic().getLoginId();
        String scope = req.getParamNotNull(SaOAuth2Consts.Param.scope);
        List<String> scopes = SaOAuth2Manager.getDataConverter().convertScopeStringToList(scope);
        SaOAuth2DataGenerate dataGenerate = SaOAuth2Manager.getDataGenerate();
        SaOAuth2Template oauth2Template = SaOAuth2Manager.getTemplate();
        if (!req.isMethod(SaHttpMethod.POST)) {
            throw (new SaOAuth2Exception("无效请求方式：" + req.getMethod())).setCode(30151);
        } else {
            oauth2Template.saveGrantScope(clientId, loginId, scopes);
            boolean buildRedirectUri = req.isParam(SaOAuth2Consts.Param.build_redirect_uri, "true");
            if (!buildRedirectUri) {
                oauth2Template.saveGrantScope(clientId, loginId, scopes);
                return SaResult.ok();
            } else {
                RequestAuthModel ra = SaOAuth2Manager.getDataResolver().readRequestAuthModel(req, loginId);
                if (SaOAuth2Consts.ResponseType.code.equals(ra.responseType)) {
                    CodeModel codeModel = dataGenerate.generateCode(ra);
                    String redirectUri = dataGenerate.buildRedirectUri(ra.redirectUri, codeModel.code, ra.state);
                    cacheNonce(codeModel.code);
                    return SaResult.ok().set(SaOAuth2Consts.Param.redirect_uri, redirectUri);
                } else if (SaOAuth2Consts.ResponseType.token.equals(ra.responseType)) {
                    AccessTokenModel at = dataGenerate.generateAccessToken(ra, false, (Consumer)null);
                    String redirectUri = dataGenerate.buildImplicitRedirectUri(ra.redirectUri, at.accessToken, ra.state);
                    return SaResult.ok().set(SaOAuth2Consts.Param.redirect_uri, redirectUri);
                } else {
                    throw (new SaOAuth2Exception("无效response_type: " + ra.responseType)).setCode(30125);
                }
            }
        }
    }
}
